package com.listeningframework.boot.codegen.generators.coders;

import com.listeningframework.boot.codegen.context.MetaContext;
import com.listeningframework.boot.codegen.exception.BusinessException;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 *
 * @description Entity Coder
 *
 * @author lixining
 * @version $Id: EntityCoder.java, v 0.1 2016年12月5日 下午1:53:23 lixining Exp $
 */
public class EntityCoder extends AbstractCoder {

    public EntityCoder(MetaContext context) {
        super(context);
    }

    @Override
    protected String getContent() throws BusinessException {
        List<String> template = getTemplate();
        if (CollectionUtils.isEmpty(template)) {
            return "";
        }
        StringBuilder builder = new StringBuilder();
        for (String str : template) {
            builder.append(str).append("\n");
        }
        return render(builder.toString());
    }

    @Override
    protected Map<String, Object> getParams() {
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put(CLASS_IMPORTS, context.getExcludeSuperImports());
        paramMap.put(CLASS_METADATA_LIST, context.getExcludeSuperMetaList());
        return paramMap;
    }

    @Override
    protected String getSavePath() throws BusinessException {
        return context.getEntityPath();
    }

    /**
     * 根据已有代码解析新模板
     *
     * @return List<String>
     * @throws BusinessException
     */
    private List<String> getTemplate() throws BusinessException {
        List<String> result = new ArrayList<>();
        BufferedReader reader = null;
        try {
            String file = getSrcJavaPath() + context.getEntityPath();
            reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "utf-8"));
            String line = null;
            boolean findImport = false;
            boolean findFields = false;
            while ((line = reader.readLine()) != null) {
                boolean isImportTag = StringUtils.contains(line, "@codegen:import");
                if (findImport && !isImportTag) {
                    continue;
                }
                boolean isFieldTag = StringUtils.contains(line, "@codegen:fields");
                if (findFields && !isFieldTag) {
                    continue;
                }
                if (isImportTag) {
                    findImport = !findImport;
                    result.add(line);
                    if (findImport) {
                        addImport(result);
                    }
                } else if (isFieldTag) {
                    findFields = !findFields;
                    result.add(line);
                    if (findFields) {
                        addFieldGetterAndSetter(result);
                    }
                } else {
                    result.add(line);
                }
            }
            return result;
        } catch (Exception e) {
            throw new BusinessException("读取原始Entity文件失败", e);
        } finally {
            IOUtils.closeQuietly(reader);
        }
    }

    /**
     * Import导入脚本
     *
     * @param result
     */
    private void addImport(List<String> result) {
        result.add("<#if classImports??>");
        result.add("<#list classImports as importItem>");
        result.add("import ${importItem};");
        result.add("</#list>");
        result.add("</#if>");
    }

    /**
     * 属性GetterSetter脚本
     *
     * @param result
     */
    private void addFieldGetterAndSetter(List<String> result) {
        // @formatter:off
        result.add("<#if classMetaDataList??>");
        result.add("<#list classMetaDataList as metaDataItem>");
        result.add("    /**");
        result.add("     * ${metaDataItem.comment!}");
        result.add("     */");
        result.add("    private ${metaDataItem.javaTypeClassSimpleName!} ${metaDataItem.javaName!};");
        result.add("</#list>");
        result.add("<#list classMetaDataList as metaDataItem>");
        result.add("");
        result.add("    /**");
        result.add("     * Getter method for property <tt>${metaDataItem.javaName!}</tt>.");
        result.add("     * ");
        result.add("     * @return property value of ${metaDataItem.javaName!}");
        result.add("     */");
        result.add("    public ${metaDataItem.javaTypeClassSimpleName!} ${metaDataItem.getterMethodName!}() {");
        result.add("        return ${metaDataItem.javaName!};");
        result.add("    }");
        result.add("");
        result.add("    /**");
        result.add("     * Setter method for property <tt>${metaDataItem.javaName!}</tt>.");
        result.add("     * ");
        result.add("     * @param ${metaDataItem.javaName!} value to be assigned to property ${metaDataItem.javaName!}");
        result.add("     */");
        result.add("    public void ${metaDataItem.setterMethodName!}(${metaDataItem.javaTypeClassSimpleName!} ${metaDataItem.javaName!}) {");
        result.add("        this.${metaDataItem.javaName!} = ${metaDataItem.javaName!};");
        result.add("    }");
        result.add("</#list>");
        result.add("</#if>");
        // @formatter:on
    }

}
